package com.example.gulimall.ware.service.impl;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.common.constant.OrderConstant;
import com.example.common.constant.WareConstant;
import com.example.common.exception.NoStockException;
import com.example.common.to.SkuHasStockTo;
import com.example.common.utils.PageUtils;
import com.example.common.utils.Query;
import com.example.common.utils.R;
import com.example.gulimall.ware.dao.WareSkuDao;
import com.example.gulimall.ware.entity.WareOrderTaskDetailEntity;
import com.example.gulimall.ware.entity.WareOrderTaskEntity;
import com.example.gulimall.ware.entity.WareSkuEntity;
import com.example.gulimall.ware.feign.OrderFeignService;
import com.example.gulimall.ware.feign.ProductFeignService;
import com.example.gulimall.ware.service.WareOrderTaskDetailService;
import com.example.gulimall.ware.service.WareOrderTaskService;
import com.example.gulimall.ware.service.WareSkuService;
import com.example.gulimall.ware.to.DetailTo;
import com.example.gulimall.ware.to.OrderTo;
import com.example.gulimall.ware.to.StockLockTo;
import com.example.gulimall.ware.vo.OrderItemVo;
import com.example.gulimall.ware.vo.SkuLockVo;
import com.example.gulimall.ware.vo.WareSkuLockVo;
import org.apache.commons.lang.StringUtils;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;


@Service("wareSkuService")
public class WareSkuServiceImpl extends ServiceImpl<WareSkuDao, WareSkuEntity> implements WareSkuService {

    @Autowired
    ProductFeignService productFeignService;
    @Autowired
    WareOrderTaskService wareOrderTaskService;
    @Autowired
    WareOrderTaskDetailService wareOrderTaskDetailService;
    @Autowired
    RabbitTemplate rabbitTemplate;
    @Autowired
    OrderFeignService orderFeignService;
    /**
     * wareId: 123,//仓库id
     * skuId: 123//商品id
     * @param params
     * @return
     */
    @Override
    public PageUtils queryPage(Map<String, Object> params) {
        QueryWrapper<WareSkuEntity> wareSkuEntityQueryWrapper = new QueryWrapper<>();
        String wareId = (String) params.get("wareId");
        if(!StringUtils.isEmpty(wareId)){
            wareSkuEntityQueryWrapper.eq("ware_id",wareId);
        }
        String skuId = (String) params.get("skuId");
        if(!StringUtils.isEmpty(skuId)){
            wareSkuEntityQueryWrapper.eq("sku_id",skuId);
        }
        IPage<WareSkuEntity> page = this.page(
                new Query<WareSkuEntity>().getPage(params),
                wareSkuEntityQueryWrapper
        );

        return new PageUtils(page);
    }

    @Override
    public void addStock(Long skuId, Long wareId, Integer skuNum) {
        List<WareSkuEntity> entities = this.list(new QueryWrapper<WareSkuEntity>()
                .eq("sku_id", skuId).eq("ware_id", wareId));
        if(entities==null||entities.size()==0){
            WareSkuEntity wareSkuEntity = new WareSkuEntity();
            wareSkuEntity.setSkuId(skuId);
            wareSkuEntity.setWareId(wareId);
            wareSkuEntity.setStock(skuNum);
            wareSkuEntity.setStockLocked(0);
            try {
                R info = productFeignService.info(wareSkuEntity.getSkuId());
                if((Integer)info.get("code")==0){
                    Map<String,Object> skuInfo = (Map<String, Object>) info.get("skuInfo");
                    wareSkuEntity.setSkuName((String) skuInfo.get("skuName"));
                }
            } catch (Exception e) {
            }
            baseMapper.insert(wareSkuEntity);
        }
        else{ baseMapper.addStock(skuId, wareId, skuNum);}

    }

    @Override
    public List<SkuHasStockTo> getSkuHasStocks(List<Long> skuIds) {
        List<SkuHasStockTo> collect = skuIds.stream().map(id -> {
            SkuHasStockTo skuHasStockTo = new SkuHasStockTo();
            skuHasStockTo.setSkuId(id);
            Long count=baseMapper.getSkuHasStocks(id);
            skuHasStockTo.setHasStock(count != null && count > 0);
            return skuHasStockTo;
        }).collect(Collectors.toList());
        return collect;
    }

    @Override
    @Transactional
    public Boolean orderLockStock(WareSkuLockVo wareSkuLockVo) {
        //创建库存工作单存储方便解锁时进行查找
        WareOrderTaskEntity wareOrderTaskEntity = new WareOrderTaskEntity();
        wareOrderTaskEntity.setOrderSn(wareOrderTaskEntity.getOrderSn());
        wareOrderTaskEntity.setCreateTime(new Date());
        wareOrderTaskService.save(wareOrderTaskEntity);
        List<OrderItemVo> itemVos = wareSkuLockVo.getItemVoList();
        List<SkuLockVo> lockVos = itemVos.stream().map(item -> {
            SkuLockVo skuLockVo = new SkuLockVo();
            skuLockVo.setSkuId(item.getSkuId());
            skuLockVo.setCount(item.getCount());
            List<Long> wareIds=baseMapper.listWareId(item.getSkuId(),item.getCount());
            skuLockVo.setWareIds(wareIds);
            return skuLockVo;
        }).collect(Collectors.toList());
        for (SkuLockVo lockVo : lockVos) {
            boolean lock=true;
            Long skuId = lockVo.getSkuId();
            List<Long> wareIds = lockVo.getWareIds();
            if(wareIds==null||wareIds.size()==0){
                throw new NoStockException(skuId);
            }else{
                for (Long wareId : wareIds) {
                    Long count=baseMapper.updateWareStock(skuId,lockVo.getCount(),wareId);
                    if(count==0){
                        lock=false;
                    }else{
                        WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity(
                                null,skuId,"",
                                lockVo.getCount(),wareOrderTaskEntity.getId(),
                                wareId,1);
                        wareOrderTaskDetailService.save(detailEntity);
                        //发送锁定库存的消息到延时队列，到时间后自动解锁库存
                        StockLockTo stockLockTo = new StockLockTo();
                        stockLockTo.setStockId(wareOrderTaskEntity.getId());
                        DetailTo detailTo = new DetailTo();
                        BeanUtils.copyProperties(detailEntity,detailTo);
                        stockLockTo.setDetailTo(detailTo);
                        rabbitTemplate.convertAndSend("stock-event-exchange","stock.locked",stockLockTo);
                        lock=true;
                        break;
                    }
                }
            }
            if(!lock) throw new NoStockException(skuId);
        }
        return true;
    }

    @Override
    public void unlock(StockLockTo stockLockTo) {
        DetailTo detailTo = stockLockTo.getDetailTo();
        WareOrderTaskDetailEntity byId = wareOrderTaskDetailService.getById(detailTo.getId());
        //存在工单详情，说明库存锁定成功，可以进行解锁
        if (byId != null) {
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(stockLockTo.getStockId());
            R orderStatus = orderFeignService.getOrderStatus(taskEntity.getOrderSn());
            if ((int) orderStatus.get("code") == 0) {
                OrderTo orderTo = orderStatus.getData(new TypeReference<OrderTo>() {
                });
                //判断order是否为空，并且状态是否是取消，如果是则解锁库存
                if (orderTo == null || orderTo.getStatus().equals(OrderConstant.OrderStatusEnum.CANCLED.getCode())) {
                    //为保证幂等性，只有当工作单详情处于被锁定的情况下才进行解锁
                    if (byId.getLockStatus().equals(WareConstant.WareTaskStatusEnum.Locked.getCode())) {
                        unlockStock(detailTo.getSkuId(), detailTo.getSkuNum(), detailTo.getWareId(),
                                byId.getId());
                    }
                }
            } else {
                //消息拒绝以后重新放在队列里面，让别人继续消费解锁
                //远程调用服务失败
                throw new RuntimeException("远程调用服务失败");
            }

        } else {
            //无需解锁
        }

    }

    @Override
    public void unlock(OrderTo orderTo) {
        //查询工单的详细信息
        String orderSn = orderTo.getOrderSn();
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getBaseMapper().
                selectOne((new QueryWrapper<WareOrderTaskEntity>()
                        .eq("order_sn", orderSn)));
        //查询出当前订单相关的且处于锁定状态的工作单详情
        List<WareOrderTaskDetailEntity> lockDetails = wareOrderTaskDetailService.
                list(new QueryWrapper
                <WareOrderTaskDetailEntity>()
                .eq("task_id", taskEntity.getId()).eq("lock_status",
                        WareConstant.WareTaskStatusEnum.Locked.getCode()));
        lockDetails.forEach(item->{
            unlockStock(item.getSkuId(),item.getSkuNum(), item.getWareId(),item.getId());
        });
    }

    private void unlockStock(Long skuId, Integer skuNum, Long wareId, Long id) {
        //库存解锁
        baseMapper.unlockStock(skuId,skuNum,wareId);
        //更新详细库存单状态
        WareOrderTaskDetailEntity wareOrderTaskDetailEntity = new WareOrderTaskDetailEntity();
        wareOrderTaskDetailEntity.setWareId(wareId);
        wareOrderTaskDetailEntity.setSkuId(skuId);
        wareOrderTaskDetailEntity.setId(id);
        wareOrderTaskDetailEntity.setLockStatus(WareConstant.WareTaskStatusEnum.hasUnLocked.getCode());
        wareOrderTaskDetailService.updateById(wareOrderTaskDetailEntity);
    }
}